package suncertify.gui.dialogs;

import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;

import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

import suncertify.application.Log;
import suncertify.application.Strings;
import suncertify.contractors.Contractor;
import suncertify.gui.ActionCommands;
import suncertify.gui.DesktopGui;
import suncertify.gui.panels.NumericValuePanel;

/**
 * Provides a {@link JDialog} for entering the owner/customer ID code value for a contractor. This dialog is shown when
 * a contractor is selected in the client application frame and the 'book' toolbar button is clicked. The dialog is
 * shown modal to its parent.
 * 
 * The dialog contains only a label and a numeric text field to enter the customer ID to which the selected contractor
 * will be assigned and an OK and cancel button. The cancel button closes the dialog and nothing else happens. The OK
 * button validates the customer ID and closes the dialog only if the data is valid, valid data means a correct eight
 * digit numeric customer ID, otherwise an error message is shown.
 * 
 * <p>
 * The only function of this dialog is to provide the eight digit customer ID value to its caller, the dialog itself
 * does not access or change any data in the database, example:
 * 
 * <pre>
 * 
 * // Create the BookingDialog with a reference to the parent window.
 * BookingDialog ownerDialog = new BookingDialog((JFrame) clientWindow);
 * ownerDialog.setVisible(true);
 * 
 * // check if the user canceled the dialog.
 * if (ownerDialog.isDialogCanceled()) {
 *     return;
 * }
 * 
 * // Get the owner ID that the user entered.
 * int ownerID = ownerDialog.getOwnerID();
 * 
 * </pre>
 * 
 */
public class BookingDialog extends JEscapeKeyDialog implements ActionListener {

    /**
     * Automatically generated serialization version ID.
     */
    private static final long serialVersionUID = 2259441104130385914L;

    /**
     * Declaration for the numeric value panel that provides the label and text field pair.
     */
    private NumericValuePanel ownerPanel;

    /**
     * True only if the cancel button is clicked.
     * 
     */
    private boolean dialogCanceled = true;

    /**
     * Constructs the dialog as follows:
     * 
     * <ol>
     * <li>Sets the title of the dialog to {@link Strings#CAP_BOOK_CONTRACTOR}</li>
     * <li>The {@link NumericValuePanel} is created and set to {@link #ownerPanel}</li>
     * <li>The {@link #buildButtonsPanel()} is called and the OK and Cancel buttons are appended to the dialog.</li>
     * <li>The dialog is set to modal, not resizable and its location is set to the center of its parent.</li>
     * </ol>
     * 
     * @param parentFrame
     *            Reference to the frame to which this dialog will be shown as modal.
     */
    public BookingDialog(JFrame parentFrame) {

	this.setTitle(Strings.CAP_BOOK_CONTRACTOR);

	this.ownerPanel = new NumericValuePanel(0, Strings.CAP_CUSTOMER_ID, Contractor.GetOwnerMaxValue(), false,
		KeyEvent.VK_I, Strings.TIP_OWNER_TEXTFIELD);

	this.setLayout(new GridLayout(2, 1));
	this.add(this.ownerPanel);
	this.add(this.buildButtonsPanel());

	this.setModal(true);
	this.setResizable(false);
	this.pack();
	this.setLocationRelativeTo(parentFrame);
    }

    /**
     * Creates a JPanel that contains the dialogs OK and cancel buttons, both buttons are aligned to the right. The OK
     * button's action command is set to {@link ActionCommands#OK} and the cancel button's action command is set to
     * {@link ActionCommands#CANCEL}.
     * 
     * @return The OK and cancel buttons panel.
     */
    private JPanel buildButtonsPanel() {

	JButton okButton = new JButton();
	JButton cancelButton = new JButton();

	okButton.setText(Strings.CAP_OK);
	okButton.setMnemonic(KeyEvent.VK_O);
	okButton.setActionCommand(ActionCommands.OK.toString());
	okButton.addActionListener(this);
	okButton.setDefaultCapable(true);

	cancelButton = new JButton(Strings.CAP_CANCEL);
	cancelButton.setMnemonic(KeyEvent.VK_C);
	cancelButton.addActionListener(this);
	cancelButton.setActionCommand(ActionCommands.CANCEL.toString());

	JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
	buttonPanel.add(okButton);
	buttonPanel.add(cancelButton);

	this.getRootPane().setDefaultButton(okButton);

	return buttonPanel;
    }

    /**
     * Called by swing when the OK or cancel buttons are clicked. The clicked buttons are identified by the
     * {@link ActionEvent} parameter that contains the {@link ActionCommands} enumeration assigned in
     * {@link #buildButtonsPanel()}.
     * 
     * <p>
     * If the OK button is clicked then value in the customer ID text field is validated by calling
     * {@link #isValueValid()}, if the value is valid then the {@link #dialogCanceled} is set to false and the dialog is
     * set to invisible by calling {@link #setVisible(boolean)}, if the value is not valid then the
     * {@link Strings#MSG_INVALID_CUSTOMER_ID} is shown in a message dialog.
     * 
     * <p>
     * If the cancel dialog is clicked then {@link #dialogCanceled} is set to true and the dialog is set to invisible.
     * 
     * <p>
     * The function catches all exceptions and shows them by calling
     * {@link DesktopGui#showPerformedActionErrorMessage(Exception)}
     * 
     * @param e
     *            See {@link ActionEvent}
     * 
     */
    public void actionPerformed(ActionEvent e) {
	try {
	    if (e.getActionCommand().equalsIgnoreCase(ActionCommands.OK.toString())) {

		if (this.isValueValid()) {
		    this.dialogCanceled = false;
		    this.setVisible(false);
		} else {
		    JOptionPane.showMessageDialog(null, Strings.MSG_INVALID_CUSTOMER_ID);
		}

	    } else if (e.getActionCommand().equalsIgnoreCase(ActionCommands.CANCEL.toString())) {

		this.dialogCanceled = true;
		this.setVisible(false);
	    }
	} catch (Exception ex) {
	    Log.logInfo("BookingDialog.actionPerformed() caught Exception. " + ex.getMessage() != null ? ex
		    .getMessage() : "");
	    DesktopGui.showPerformedActionErrorMessage(ex);
	}
    }

    /**
     * Determines if the dialog contains a valid customer ID when the OK button is clicked.
     * 
     * @return True if the customer ID applies to {@link Contractor#isOwnerValid(int)}, returns false otherwise.
     */
    private boolean isValueValid() {

	if (this.ownerPanel.isEmpty()) {
	    return false;
	}

	return Contractor.isOwnerValid(this.ownerPanel.getValue());
    }

    /**
     * Determines if the dialog was canceled by clicking the cancel button.
     * 
     * @return True if the cancel button was clicked, false otherwise.
     */
    public boolean isDialogCanceled() {

	return this.dialogCanceled;
    }

    /**
     * Returns the owner ID typed by the use in the text field. Note call this function only if
     * {@link #isDialogCanceled()} returns false.
     * 
     * @return The customer ID entered by the user.
     */
    public int getOwnerID() {

	return this.ownerPanel.getValue();
    }
}
